#include "Lista.h"

Lista::Lista() {
    _punteroADato = NULL;
}

Lista::Lista(string valor){
	/*this->_valor = atof(valor.c_str());*/
}

Lista::Lista(void* punteroADato){
    this->_punteroADato = punteroADato;
}

void* Lista::damePunteroAMemoria() {
    // TODO aca deberia ir una lista
    return this->_punteroADato;
}

void Lista::comparar(TipoDeDato& tipoDeDato,ostream& out) {
    NodoLista* otroValor = (NodoLista*) tipoDeDato.damePunteroADato();
    NodoLista* esteValor = (NodoLista*) this->_punteroADato;

    if ( Lista::esCircular(esteValor) ) {
        out << "La lista esperada es circular." << endl;
        return;
    }
    if ( Lista::esCircular(otroValor) ) {
        out << "La lista obtenida es circular." << endl;
        return;
    }

    int esteTamano = Lista::dameTamano(esteValor);
    int otroTamano = Lista::dameTamano(otroValor);

    int hasta = min(esteTamano,otroTamano);

    NodoLista* esteActual = esteValor;
    NodoLista* otroActual = otroValor;
    for ( int i = 0; i < hasta; i++ ) {
        if ( esteActual->valor != otroActual->valor ) {
            out << "Diferencia en el nodo " << i << " . Se esperaba " << esteActual->valor << " y se obtuvo " << otroActual->valor << endl;
        }
        esteActual = esteActual->siguienteNodo;
        otroActual = otroActual->siguienteNodo;
    }

    int diferencia = abs(esteTamano - otroTamano);

    esteActual = esteValor;
    otroActual = otroValor;
    if ( diferencia != 0 ) {
        if (esteTamano > otroTamano) {
            out << "La lista esperada tiene mas nodos que la lista obtenida. Detalle:" << endl;
            int i = 1;
            while ( i <= otroTamano ) {
                esteActual = esteActual->siguienteNodo;
                i++;
            }
            while ( esteActual != NULL )  {
                out << "El nodo " << i << " vale " << esteActual->valor << endl;
                esteActual = esteActual->siguienteNodo;
                i++;
            }
        } else {
            out << "La lista obtenida tiene mas nodos que la lista esperada. Detalle:" << endl;
            int i = 1;
            while ( i <= esteTamano ) {
                otroActual = otroActual->siguienteNodo;
                i++;
            }
            while ( otroActual != NULL )  {
                out << "El nodo " << i << " vale " << otroActual->valor << endl;
                otroActual = otroActual->siguienteNodo;
                i++;
            }
        }
    }
}

ClaseDeDato Lista::getClass() {
    return C_LISTA;
}

Lista::~Lista(){
    list<NodoLista*> listaPunteros;
    NodoLista* temp = (NodoLista*)_punteroADato;

    while (  ( temp != NULL ) && ( !buscarPuntero(listaPunteros,temp) ) ) {
        NodoLista* actual = temp;
        listaPunteros.push_back(actual);
        temp = temp->siguienteNodo;
        //delete actual;
        freeParametro(actual);
    }
}

void Lista::agregarElemento(int valor){
    if ( _punteroADato == NULL ) {
        //NodoLista* nodoNuevo = new NodoLista;
        NodoLista* nodoNuevo = (NodoLista*) mallocParametro(sizeof(NodoLista));
        nodoNuevo->valor = valor;
        nodoNuevo->siguienteNodo = NULL;
        _punteroADato = nodoNuevo;
    } else {
        NodoLista* nodoFinal = buscarNodoFinal();
        //NodoLista* nodoNuevo = new NodoLista;
        NodoLista* nodoNuevo = (NodoLista*) mallocParametro(sizeof(NodoLista));
        nodoNuevo->valor = valor;
        nodoNuevo->siguienteNodo = NULL;
        nodoFinal->siguienteNodo = nodoNuevo;
    }

    tamano++;
}

int Lista::dameTamano(NodoLista* nodo){
    int i = 0;

    while ( nodo != NULL ) {
        nodo = nodo->siguienteNodo;
        i++;
    }

    return i;
}

NodoLista* Lista::buscarNodoFinal(){
    NodoLista* temp = (NodoLista*)_punteroADato;

    while(temp->siguienteNodo != NULL){
        temp = temp->siguienteNodo;
    }

    return temp;
}

bool Lista::esCircular(NodoLista* nodoActual) {
    list<NodoLista*> listaPunteros;
    int resultado = false;

    while (nodoActual != NULL && !resultado) {
        if (Lista::buscarPuntero(listaPunteros, nodoActual))
            resultado = true;
        listaPunteros.push_back(nodoActual);
        nodoActual = nodoActual->siguienteNodo;
    }

    return resultado;
}

bool Lista::buscarPuntero(list<NodoLista*>& lista, NodoLista* nodo) {
    for ( list<NodoLista*>::iterator it = lista.begin(); it != lista.end(); it++ ) {
        if ( nodo == *it ) {
            return true;
        }
    }

    return false;
}
